package com.symaster.backups.frame.element.card;


import com.symaster.backups.util.AnimationUtil;
import com.symaster.common.animation.Curve;
import lombok.Getter;

import javax.swing.*;
import java.awt.*;

import static com.symaster.backups.util.TimeUtil.floatTime;


/**
 * @author yinmiao
 * @version 2023/12/4
 */
public class CardPanel extends JComponent {
    private static final float times = 150f;
    private static final Curve curve = Curve.TYPE_FAST_TO_SLOW;

    @Getter
    private int viewIndex = 0;

    @Getter
    private Integer changeIndex;
    private Float changeTime;
    private boolean change = false;
    private final PaintRunnable paintRunnable;

    public CardPanel() {
        this.paintRunnable = new PaintRunnable(this);
    }

    public void setViewIndex(int viewIndex) {
        int src = this.viewIndex;
        if (src == viewIndex) {
            return;
        }

        this.changeIndex = viewIndex;
        this.changeTime = floatTime();
        this.change = true;
        SwingUtilities.invokeLater(paintRunnable);
    }

    @Override
    public void removeAll() {
        this.change = false;
        this.changeTime = null;
        this.viewIndex = 0;
        this.changeIndex = null;
        super.removeAll();
    }

    @Override
    public void paint(Graphics g) {
        final int width = getWidth();
        final int height = getHeight();
        Component[] components = getComponents();

        if (components.length > 0) {
            if (changeIndex != null) {
                components[changeIndex].setVisible(true);
            }

            for (Component component : components) {
                component.setSize(width, height);
            }

            int xOffset;
            if (this.change) {
                float v = floatTime() - changeTime;
                if (v >= times) {
                    this.viewIndex = changeIndex;
                    xOffset = -(width * viewIndex);
                    this.change = false;
                } else {
                    int srcPoint = -(this.viewIndex * width);
                    int dstPoint = -(this.changeIndex * width);
                    float point = (float) AnimationUtil.getPoint(curve, v / times);

                    float v1 = point * (dstPoint - srcPoint) + srcPoint;
                    xOffset = Math.round(v1);
                }
            } else {
                xOffset = -(width * viewIndex);
            }

            for (int i = 0; i < components.length; i++) {
                Component component = components[i];
                component.setBounds(i * width + xOffset, 0, width, height);
                component.doLayout();
            }

            super.paint(g);
            if (this.change) {
                SwingUtilities.invokeLater(paintRunnable);
            } else {
                for (int i = 0; i < components.length; i++) {
                    if (i != viewIndex) {
                        components[i].setVisible(false);
                    }
                }
            }
        } else {
            super.paint(g);
        }
    }

    public static class PaintRunnable implements Runnable {

        private final CardPanel cardPanel;

        public PaintRunnable(CardPanel cardPanel) {
            this.cardPanel = cardPanel;
        }

        @Override
        public void run() {
            cardPanel.repaint();
            for (Component component : cardPanel.getComponents()) {
                component.repaint();
            }
        }
    }

}
